<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>物流地图 - 天地图 + Leaflet</title>
    <link rel="stylesheet" href="./css/leaflet.css" />
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      #map {
        height: 100vh;
        width: 100vw;
      }

      /* 自定义弹窗样式 */
      .leaflet-popup-content-wrapper {
        color: #fff;
        background-color: #00000060;
        backdrop-filter: blur(10px);
        box-shadow: none;
      }
      .leaflet-popup-tip-container {
        display: none;
      }

      .map-tooltip {
        color: #a6283f;
        background: none;
        border: none;
        box-shadow: none;
        font-weight: 600;
        font-size: 20px;
      }
      .leaflet-tooltip-top:before,
      .leaflet-tooltip-bottom:before,
      .leaflet-tooltip-left:before,
      .leaflet-tooltip-right:before {
        display: none;
      }

      /* 定义闪烁动画 */
      @keyframes blink {
        0% {
          opacity: 1;
        }
        50% {
          opacity: 0;
        }
        100% {
          opacity: 1;
        }
      }

      /* 应用动画到图标 */
      .blinking-icon {
        animation: blink 1s infinite; /* 1秒闪烁一次 */
      }
    </style>
  </head>
  <body>
    <div id="map"></div>

    <!-- <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script> -->
    <script src="./js/leaflet.js"></script>
    <script src="./js/leaflet-moving-marker.js"></script>
    <script>
      function handleResize() {
        const width = window.innerWidth;
        const height = window.innerHeight;
        map.invalidateSize();
      }

      // 添加防抖
      const debouncedHandleResize = debounce(handleResize, 200);
      window.addEventListener("resize", debouncedHandleResize);

      // 初始化时调用一次
      // handleResize();

      // 防抖函数
      function debounce(func, wait) {
        let timeout;
        return function (...args) {
          clearTimeout(timeout);
          timeout = setTimeout(() => func.apply(this, args), wait);
        };
      }

      const group = L.layerGroup(); //图层组

      //设置标记的默认icon
      const DefaultIcon = L.icon({
        iconUrl: "./icon/marker-icon.png",
        iconSize: [25, 41],
        iconAnchor: [12, 40],
      });
      L.Marker.prototype.options.icon = DefaultIcon;

      // 初始化地图
      const map = L.map("map", {
        minZoom: 0.5, //地图的最小缩放级别
        maxZoom: 18, //地图的最大缩放级别
        center: [39.9, 116.41], //地图初始化时的中心点位置
        zoom: 3, //地图初始化时的缩放等级
        attributionControl: false, //隐藏版权信息控件
        zoomSnap: 0.5, // 缩放级别步长为 0.5
        zoomDelta: 0.5, // 缩放级别步长为 0.5
        trackResize: false, //禁用自动调整大小功能（通过其他逻辑控制）
        maxBoundsViscosity: 0.5, //控制地图边界限制的“粘性”，值越接近 1 越难拖出边界
        maxBounds: L.latLngBounds(L.latLng(-90, -540), L.latLng(90, 540)), //设置地图可拖动的最大边界范围，支持跨半球滚动（经度范围 -540 到 540）
      });
      // 将地图的缩放控件移动到右下角
      map.zoomControl.setPosition("bottomright");

      // 添加天地图图层
      const tianLayer = L.tileLayer(
        "http://t0.tianditu.gov.cn/ter_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=aec4c179ae6ca0ac91bc735434ca09f8"
      ).addTo(map);
      L.tileLayer(
        "http://t0.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=aec4c179ae6ca0ac91bc735434ca09f8"
      ).addTo(map);

      group.addTo(map);

      // 船运路径数据
      const shipPath = [
        [31.23, 121.47],
        [35.6895, 139.6917],
      ];

      let direction = 0;
      /**
       * 处理经度
       * 当轨迹经过-180或180度时，为了把从180与-180度断开的后续点的经度转成连贯的，以保证线的连续
       * @param lon 经度
       * @returns 处理后的经度
       */
      const getLon = (lon) => {
        return direction * 360 + lon;
      };
      /**
       * 处理坐标
       * 当轨迹的经度经过-180或180度时，把线变成连续
       * 第一种情况:
       * 从东半球向西半球走，当前轨迹为[[0, 175], [0, 179], [0, -178], [0, -175]]
       *   -180--------------------------0-----------------------------180
       *   |                             |                             |
       *   |                             |                             |
       *   |                             |                             |
       *   |··                           |                           ··|
       *   |                             |                             |
       *   |                             |                             |
       *   |                             |                             |
       *   -------------------------------------------------------------
       * 在该方法转换时，处理到[0, -178]这个点direction会变成1，之后都不会再改变
       * getLon方法会把之后的负的点都加360，变成正的，所以最后变成[[0, 175], [0, 179], [0, 182], [0, 175]]
       * 这样就保证了线的连续性
       *   -180--------------------------0-----------------------------180
       *   |                             |                             |
       *   |                             |                             |
       *   |                             |                             |
       *   |                             |                           ··|··
       *   |                             |                             |
       *   |                             |                             |
       *   |                             |                             |
       *   -------------------------------------------------------------
       *
       * 第二种情况:
       * 从西半球向东半球走，当前轨迹为[[0, -175], [0, -179], [0, 178], [0, 175]]
       *   -180--------------------------0-----------------------------180
       *   |                             |                             |
       *   |                             |                             |
       *   |                             |                             |
       *   |··                           |                           ··|
       *   |                             |                             |
       *   |                             |                             |
       *   |                             |                             |
       *   -------------------------------------------------------------
       * 在该方法转换时，处理到[0, 178]这个点direction会变成-1，之后都不会再改变
       * getLon方法会把之后的正的点都减360，变成负的，所以最后变成[[0, -175], [0, -179], [0, -182], [0, -175]]
       * 这样就保证了线的连续性
       *   -180--------------------------0-----------------------------180
       *   |                             |                             |
       *   |                             |                             |
       *   |                             |                             |
       * ··|··                           |                             |
       *   |                             |                             |
       *   |                             |                             |
       *   |                             |                             |
       *   -------------------------------------------------------------
       */
      const formatLatLngs = (points) => {
        direction = 0;
        return points.map((point, i, arr) => {
          const lat = point[0];
          const lon = point[1];
          if (i >= 1 && Math.abs(arr[i - 1][1] - lon) > 180) {
            direction += lon < 0 ? 1 : -1;
          }
          return [lat, getLon(lon)];
        });
      };

      const latlngs = formatLatLngs(shipPath);
      // 起点
      const startPoint = latlngs[0];
      // 终点
      const endPoint = latlngs[latlngs.length - 1];

      // 起始点
      const startMarker = L.marker(startPoint, {}).addTo(group);
      startMarker
        .bindTooltip("上海", {
          permanent: true,
          className: "map-tooltip",
        })
        .openTooltip();

      const emptyIcon = L.divIcon({
        html: "", // 空内容
        iconSize: [0, 0], // 图标大小为 0
        className: "leaflet-empty-icon", // 自定义类名（可选）
      });
      // 终点
      const endMarker = L.marker(endPoint, {
        icon: emptyIcon,
      }).addTo(group);
      endMarker
        .bindTooltip("东京", {
          permanent: true,
          className: "map-tooltip",
          offset: [20, -20],
        })
        .openTooltip();

      // 绘制已经走过的路径
      const hasCrossPathLine = L.polyline([...latlngs], {
        // weight: 3,
        // opacity: 0.7,
        color: "#3287EA",
        noClip: true,
      }).addTo(group);
      let pathBounds = hasCrossPathLine.getBounds();

      //  当前位置
      const currentLocationLatLng = [35.6895, 139.6917];
      // 下一港位置
      const endLocationLatLng = [40.7128, -74.006];
      const latlngs2 = formatLatLngs([
        currentLocationLatLng,
        endLocationLatLng,
      ]);
      const nextMarker = L.marker(latlngs2[1], {}).addTo(group);
      nextMarker
        .bindTooltip("纽约", {
          permanent: true,
          className: "map-tooltip",
        })
        .openTooltip();

      // 绘制下一港的轨迹
      const nextPathLine = L.polyline([...latlngs2], {
        weight: 3,
        // opacity: 0.7,
        color: "#3287EA",
        dashArray: "10,15",
        noClip: true,
      }).addTo(group);
      pathBounds = pathBounds.extend(nextPathLine.getBounds());

      // 当前位置的marker
      L.marker(currentLocationLatLng, {
        icon: L.icon({
          iconUrl: "./icon/bomb.png",
          iconSize: [50, 50],
          iconAnchor: [25, 25],
          // className: "map-current-location-icon",
          className: "blinking-icon", // 应用闪烁动画
        }),
        zIndexOffset: 10,
      })
        .addTo(group)
        .bindPopup(
          `<div>
            <div>船运路径</div>
            <div>当前站：东京</div>
            <div>下一站：纽约</div>
          </div>`,
          {
            autoClose: false,
            closeButton: false,
            offset: [80, -10],
            className: "map-current-location-popup",
          }
        )
        .openPopup();

      // marker
      const radarIcon = L.icon({
        iconUrl: "./icon/radar.png",
        iconSize: [50, 50],
        iconAnchor: [15, 15],
        className: "blinking-icon", // 应用闪烁动画
      });
      const taiwanMarker = L.marker([13.4443, 144.7937], {
        icon: radarIcon,
      }).addTo(group);

      taiwanMarker
        .bindTooltip("关岛基地", {
          permanent: true,
          className: "map-tooltip",
          offset: [-120, -20],
        })
        .openTooltip();

      map.fitBounds(pathBounds, { padding: [100, 100] });

      const moveMarker = L.Marker.movingMarker(
        [...latlngs, latlngs2[1]],
        5000,
        {
          autostart: true,
          loop: true,
          rotate: true,
          rotationRange: [-180, 180],
        }
      ).addTo(group);
      const moveIcon = L.icon({
        iconUrl: "./icon/icon_plane.png",
        iconSize: [50, 50],
        iconAnchor: [25, 25],
      });
      moveMarker.setIcon(moveIcon).addTo(group);

      // moveMarker.on('click',function(e){
      //   moveMarker.start()
      // })
    </script>
  </body>
</html>
